// codec_ieee754
//float32位单精度浮点数在机器中表示用 1 位表示数字的符号，用 8 位表示指数，用 23 位表示尾数。
// double64位双精度浮点数，用 1 位表示符号，用 11 位表示指数，52 位表示尾数。
package codec

import (
	"encoding/binary"
	"math"
)

//将f按ieee754格式编码，返回大端字节数组
//float32位单精度浮点数：用1位表示数字的符号，用8位表示指数，用23位表示尾数
func Ieee754Encode32(f float32) []byte {
	buf := make([]byte, 4)
	bits := math.Float32bits(f)
	binary.BigEndian.PutUint32(buf, bits)
	return buf
}

//按ieee7554格式将4个字节解码为float32数
//buf为大端字节序
func Ieee754Decode32(buf []byte) float32 {
	v := binary.BigEndian.Uint32(buf)
	f := math.Float32frombits(v)
	return f
}

//按ieee7554格式将4个字节解码为float32数
func Ieee754Decode32_a(d3, d2, d1, d0 byte) float32 {
	//	var v uint32
	v := (uint32(d3) << 24) | (uint32(d2) << 16) | (uint32(d1) << 8) | uint32(d0)
	Fraction23b := v & 0x7fffff
	Exp8 := (v >> 23) & 0xff
	if Fraction23b == 0 && Exp8 == 0 {
		return float32(0)
	}
	Sign := v >> 31

	var exp, fraction float64
	if Fraction23b != 0 {
		for i, f := float64(23), Fraction23b; i >= 0; i-- {
			if f%2 == 1 {
				fraction += 1 / math.Pow(2, i)
			}
			f >>= 1
		}
	}
	/**
	如果浮点数的指数部分的编码值是0，分数部分非零，那么这个浮点数将被称为非规约形式的浮点数。
	一般是某个数字相当接近零时才会使用非规约型式来表示。
	IEEE 754标准规定：非规约形式的浮点数的指数偏移值比规约形式的浮点数的指数偏移值小1。
	规约浮点数的尾数大于等于1且小于2，而非规约浮点数的尾数小于1且大于0。
	**/
	if Exp8 == 0 { //非规约形式
		exp = float64(-126)
	} else {
		exp = float64(Exp8) - 127
		fraction = fraction + 1
	}
	//	val := math.Pow(-1, float64(Sign)) * math.Pow(2, exp) * fraction
	val := math.Pow(2, exp) * fraction
	if Sign == 1 {
		val *= -1
	}
	// log.Printf("%08x, %x,%02x,%06x %f,%f %f", v, Sign, Exp8, Fraction23b, exp, fraction, val)

	return float32(val)
}
